//ini file i/o
//$Id: ini_file.h 608 2010-11-28 16:30:05Z andrew.tsyganov $
#pragma once

//"MIT license is an academic license"
#include "contrib/simpleini/SimpleIni.h"

#include "src/heo/include/reflection.h"

//__________________________________________________________________________________
namespace ini
{
//__________________________________________________________________________________
class file
{
    DISALLOW_COPY_AND_ASSIGN(file);
public:
    CSimpleIniCaseA ini_;

    file()
    {ini_.SetMultiLine(true);}///

    bool load(char const* szFile) 
    {
        return ini_.LoadFile(szFile) >= SI_OK;
    }

    bool save(char const* szFile)
    {
        return ini_.SaveFile(szFile) >= SI_OK;
    }
};
//__________________________________________________________________________________
class in:
    public meta::visitor<in>
{
    file&       file_;
    std::string section_;
public:
    explicit in(file& f, char const* szSection = ""): file_(f), section_(szSection)
    {}

    template<class T>
    in& operator >>(T& t)
    {
        visit_T(t);
        return *this;
    }

    template<typename T, typename D>
    void visit_Class(T& t, char const*, D const&)
    {
        char const* name = T::get_Section();
        if (name)
        {
            in inner(file_, name);
            t.accept(inner);
        }
        else
            t.accept(*this);
    }

    template<typename T, typename D>
    void visit(T& t, char const* szName, D const& d)
    {
        if (!*szName)
            return;
        ASSERT_(section_.length() > 0);
        char const* def = "";
        char const* value = file_.ini_.GetValue(section_.c_str(), szName, def);
        if (def == value)
            meta::Set_Default(t, d);
        else
        {
            meta::From_String(t, szName, value, d);
        }
    }

    template<typename T, typename D>
    void visit_Array(T* pt, size_t N, char const* szName, D const& d)
    {}
    template<typename T, typename D>
    void visit_Ptr(T* pt, char const* szName, D const& d)
    {}
};
//__________________________________________________________________________________
//__________________________________________________________________________________
class out:
    public meta::visitor<out>
{
    file&       file_;
    std::string section_;
public:
    explicit out(file& f, char const* szSection = ""): file_(f), section_(szSection)
    {}

    template<class T>
    out& operator <<(T& t)
    {
        visit_T(t);
        return *this;
    }

    template<typename T, typename D>
    void visit_Class(T& t, char const*, D const&)
    {
        char const* name = T::get_Section();
        if (name)
        {
            out inner(file_, name);
            t.accept(inner);
        }
        else
            t.accept(*this);
    }

    template<typename T, typename D>
    void visit(T& t, char const* szName, D const& d)
    {
        if (!*szName)
            return;
        ASSERT_(section_.length() > 0);
        std::string s;
        char const* str = meta::Value2String(t, s);
        file_.ini_.SetValue(section_.c_str(), szName, str);
    }

    template<typename T, typename D>
    void visit_Array(T* pt, size_t N, char const* szName, D const& d)
    {}
    template<typename T, typename D>
    void visit_Ptr(T* pt, char const* szName, D const& d)
    {}
};
//__________________________________________________________________________________
}//ini
//__________________________________________________________________________________

//EOF!
